package org.summer.lawyer.pay.client.impl.wechat;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBatchDetailResult;
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.summer.common.core.exception.ServiceException;
import org.summer.common.json.utils.JsonUtils;
import org.summer.lawyer.constant.enums.PayOrderStatus;
import org.summer.lawyer.constant.enums.PayRefundStatus;
import org.summer.lawyer.constant.enums.PayTransferStatus;
import org.summer.lawyer.domain.bo.payorder.PayOrderBo;
import org.summer.lawyer.domain.bo.payrefund.PayRefundBo;
import org.summer.lawyer.domain.bo.paytransfer.PayTransferBo;
import org.summer.lawyer.domain.vo.paychannel.PayChannelVo;
import org.summer.lawyer.domain.vo.payorder.PayOrderVo;
import org.summer.lawyer.domain.vo.payrefund.PayRefundVo;
import org.summer.lawyer.domain.vo.paytransfer.PayTransferVo;
import org.summer.lawyer.pay.client.impl.AbstractPayClient;

import java.io.File;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cn.hutool.core.date.DatePattern.*;

/**
 *
 */
@Slf4j
public abstract class AbstractWeChatPayClient extends AbstractPayClient {

    protected WxPayService wxPayService;

    public AbstractWeChatPayClient(PayChannelVo vo) {
        super(vo);
    }

    /**
     * @param tradeType 交易类型
     */
    protected void doInit(String tradeType) {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setApiV3Key(channel.getApiKeyThree());
        payConfig.setAppId(channel.getWxAppId());
        payConfig.setMchId(channel.getMchNo());
        payConfig.setTradeType(tradeType);
        // weixin-pay-java 无法设置内容，只允许读取文件，所以这里要创建临时文件来解决
        if (Base64.isBase64(channel.getKeyContent())) {
            payConfig.setKeyPath(this.createTempFile(Base64.decode(channel.getKeyContent())).getPath());
        }
        if (StrUtil.isNotEmpty(channel.getPrivateKeyContent())) {
            payConfig.setPrivateKeyPath(this.createTempFile(channel.getPrivateKeyContent()).getPath());
        }
        if (StrUtil.isNotEmpty(channel.getPrivateCertContent())) {
            payConfig.setPrivateCertPath(this.createTempFile(channel.getPrivateCertContent()).getPath());
        }
        //创建支付服务
        wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
    }

    @Override
    protected PayOrderVo doUnifiedPay(PayOrderBo bo) throws Exception {
        try {
            return switch (channel.getApiVersion()) {
                case WeChatPayClientConfig.API_VERSION_V2 -> doUnifiedPayV2(bo);
                case WeChatPayClientConfig.API_VERSION_V3 -> doUnifiedPayV3(bo);
                default -> throw new ServiceException(StrUtil.format("未知的 API 版本({})", channel.getApiVersion()));
            };
        } catch (WxPayException e) {
            log.error("调用支付渠道失败，{}", e.getMessage());
            PayOrderVo vo = new PayOrderVo();
            String errorCode = getErrorCode(e);
            String errorMessage = getErrorMessage(e);
            vo.setPayStatus(PayOrderStatus.CLOSED.getCode());
            vo.setResultCode(errorCode);
            vo.setResultMsg(errorMessage);
            vo.setTradeNo(bo.getTradeNo());
            vo.setReturnJson(e.getXmlString());
            return vo;
        }
    }

    /**
     * V2版本 调用支付通道，统一下单
     *
     * @param bo 下单信息
     * @return 支付通道返回结果
     */
    protected abstract PayOrderVo doUnifiedPayV2(PayOrderBo bo) throws WxPayException;

    /**
     * V3版本 调用支付通道，统一下单
     *
     * @param bo 下单信息
     * @return 支付通道返回结果
     */
    protected abstract PayOrderVo doUnifiedPayV3(PayOrderBo bo) throws WxPayException;


    /**
     * V2版本,创建微信下单请求
     *
     * @param bo 下单信息
     * @return 下单请求
     */
    protected WxPayUnifiedOrderRequest buildUnifiedPayRequestV2(PayOrderBo bo) {
        return WxPayUnifiedOrderRequest.newBuilder()
                .outTradeNo(bo.getPayNo())
                .body(bo.getSubject())
                .detail(bo.getBody())
                .totalFee(bo.getAmount().intValue())
                .timeExpire(formatDateV2(bo.getExpireTime()))
                // .spbillCreateIp(bo.getUserIp())
                .notifyUrl(bo.getNotifyUrl())
                .build();
    }

    protected WxPayUnifiedOrderV3Request buildUnifiedPayRequestV3(PayOrderBo bo) {
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setOutTradeNo(bo.getPayNo());
        request.setDescription(bo.getSubject());
        request.setDescription(bo.getSubject());
        request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(bo.getAmount().intValue()));
        request.setTimeExpire(formatDateV3(bo.getExpireTime()));
        // request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(bo.getUserIp()));
        request.setNotifyUrl(bo.getNotifyUrl());
        return request;
    }

    @Override
    protected PayOrderVo doParseOrderNotify(Map<String, String> params, String body) throws WxPayException {
        return switch (channel.getApiVersion()) {
            case WeChatPayClientConfig.API_VERSION_V2 -> doParseOrderNotifyV2(body);
            case WeChatPayClientConfig.API_VERSION_V3 -> doParseOrderNotifyV3(body);
            default -> throw new ServiceException(StrUtil.format("未知的 API 版本({})", channel.getApiVersion()));
        };
    }

    private PayOrderVo doParseOrderNotifyV2(String body) throws WxPayException {
        //1.解析回调
        WxPayOrderNotifyResult response = wxPayService.parseOrderNotifyResult(body);
        //2.构建结果
        // V2 微信支付的回调，只有 SUCCESS 支付成功、CLOSED 支付失败两种情况，无需像支付宝一样解析的比较复杂
        Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ?
                PayOrderStatus.SUCCESS.getCode() : PayOrderStatus.CLOSED.getCode();
        PayOrderVo vo = new PayOrderVo();
        vo.setPayStatus(status);
        vo.setTradeNo(response.getTransactionId());
        vo.setOpenId(response.getOpenid());
        vo.setSuccessTime(parseDateV2(response.getTimeEnd()));
        vo.setPayNo(response.getOutTradeNo());
        vo.setRawData(body);
        vo.setReturnJson(body);
        return vo;
    }

    private PayOrderVo doParseOrderNotifyV3(String body) throws WxPayException {
        //1. 解析回调
        WxPayNotifyV3Result response = wxPayService.parseOrderNotifyV3Result(body, null);
        WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
        //log.info("[doParseOrderNotifyV3][支付回调结果]：{}", JsonUtils.toJsonString(result));
        //2. 构建结果
        Integer status = parseStatus(result.getTradeState());
        String openId = result.getPayer() != null ? result.getPayer().getOpenid() : null;
        PayOrderVo vo = new PayOrderVo();
        vo.setPayStatus(status);
        vo.setTradeNo(result.getTransactionId());
        vo.setOpenId(openId);
        vo.setSuccessTime(parseDateV3(result.getSuccessTime()));
        vo.setPayNo(result.getOutTradeNo());
        vo.setRawData(body);
        vo.setReturnJson(JsonUtils.toJsonString(result));
        return vo;
    }

    @Override
    protected PayOrderVo doGetPayOrder(String payNo) throws Throwable {
        try {
            return switch (channel.getApiVersion()) {
                case WeChatPayClientConfig.API_VERSION_V2 -> doGetPayOrderV2(payNo);
                case WeChatPayClientConfig.API_VERSION_V3 -> doGetPayOrderV3(payNo);
                default -> throw new ServiceException(StrUtil.format("未知的 API 版本({})", channel.getApiVersion()));
            };
        } catch (WxPayException e) {
            if (equalsAny(e.getErrCode(), "ORDERNOTEXIST", "ORDER_NOT_EXIST")) {
                String errCode = getErrorCode(e);
                String errorMessage = getErrorMessage(e);
                PayOrderVo vo = new PayOrderVo();
                vo.setPayStatus(PayOrderStatus.CLOSED.getCode());
                vo.setPayNo(payNo);
                vo.setResultCode(errCode);
                vo.setResultMsg(errorMessage);
                vo.setRawData(e.getXmlString());
                vo.setReturnJson(e.getXmlString());
                return vo;
            }
            throw e;
        }
    }

    private PayOrderVo doGetPayOrderV2(String payNo) throws WxPayException {
        // 构建 WxPayUnifiedOrderRequest 对象
        WxPayOrderQueryRequest request = WxPayOrderQueryRequest.newBuilder()
                .outTradeNo(payNo).build();
        // 执行请求
        WxPayOrderQueryResult response = wxPayService.queryOrder(request);
        //转换结果
        Integer status = parseStatus(response.getTradeState());
        PayOrderVo vo = new PayOrderVo();
        vo.setPayStatus(status);
        vo.setTradeNo(response.getTransactionId());
        // vo.setTransactionId(response.getTransactionId());
        vo.setOpenId(response.getOpenid());
        vo.setSuccessTime(parseDateV2(response.getTimeEnd()));
        vo.setPayNo(payNo);
        vo.setRawData(response);
        vo.setReturnJson(response.getXmlString());
        return vo;
    }

    private PayOrderVo doGetPayOrderV3(String payNo) throws WxPayException {
// 构建 WxPayUnifiedOrderRequest 对象
        WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request().setOutTradeNo(payNo);
        //执行请求
        WxPayOrderQueryV3Result response = wxPayService.queryOrderV3(request);
        //转换结果
        Integer status = parseStatus(response.getTradeState());
        String openId = response.getPayer() != null ? response.getPayer().getOpenid() : null;
        PayOrderVo vo = new PayOrderVo();
        vo.setPayStatus(status);
        // vo.setTransactionId(response.getTransactionId());
        vo.setTradeNo(response.getTransactionId());
        vo.setOpenId(openId);
        vo.setSuccessTime(parseDateV3(response.getSuccessTime()));
        vo.setPayNo(payNo);
        vo.setRawData(response);
        vo.setReturnJson(JSONUtil.toJsonStr(response));
        return vo;
    }

    @Override
    protected PayRefundVo doUnifiedRefund(PayRefundBo bo) throws Throwable {
        try {
            return switch (channel.getApiVersion()) {
                case WeChatPayClientConfig.API_VERSION_V2 -> doUnifiedRefundV2(bo);
                case WeChatPayClientConfig.API_VERSION_V3 -> doUnifiedRefundV3(bo);
                default -> throw new ServiceException(StrUtil.format("未知的 API 版本({})", channel.getApiVersion()));
            };
        } catch (WxPayException e) {
            String errorCode = getErrorCode(e);
            String errorMessage = getErrorMessage(e);
            return PayRefundVo.failureOf(errorCode, errorMessage, bo.getRefundNo(), e.getXmlString());
        }
    }

    private PayRefundVo doUnifiedRefundV2(PayRefundBo bo) throws Throwable {
        // 1. 构建 WxPayRefundRequest 请求
        WxPayRefundRequest request = new WxPayRefundRequest()
                .setOutTradeNo(bo.getPayNo())
                .setOutRefundNo(bo.getRefundNo())
                .setRefundFee(bo.getRefundPrice().intValue())
                .setRefundDesc(bo.getRefundReason())
                .setTotalFee(bo.getAmount().intValue())
                .setNotifyUrl(bo.getNotifyUrl());
        //2 执行请求
        WxPayRefundResult response = wxPayService.refundV2(request);
        //3 创建返回结果
        if (Objects.equals("SUCCESS", response.getResultCode())) {
            // V2 情况下，不直接返回退款成功，而是等待异步通知
            return PayRefundVo.pendingOf(response.getRefundId(), bo.getRefundNo(), response);
        }
        return PayRefundVo.failureOf(bo.getRefundNo(), response);
    }

    private PayRefundVo doUnifiedRefundV3(PayRefundBo bo) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
        WxPayRefundV3Request request = new WxPayRefundV3Request()
                .setOutTradeNo(bo.getPayNo())
                .setOutRefundNo(bo.getRefundNo())
                .setAmount(new WxPayRefundV3Request.Amount().setRefund(bo.getRefundPrice().intValue())
                        .setTotal(bo.getAmount().intValue()).setCurrency("CNY"))
                .setReason(bo.getRefundReason())
                .setNotifyUrl(bo.getNotifyUrl());
        //2 执行请求
        WxPayRefundV3Result response = wxPayService.refundV3(request);
        //3 创建返回结果
        PayRefundVo vo = new PayRefundVo();
        if (Objects.equals("SUCCESS", response.getStatus())) {
            return PayRefundVo.successOf(response.getRefundId(), bo.getRefundNo(), parseDateV3(response.getSuccessTime()), response);
        }
        if (Objects.equals("PROCESSING", response.getStatus())) {
            return PayRefundVo.pendingOf(response.getRefundId(), bo.getRefundNo(), response);
        }
        return PayRefundVo.failureOf(bo.getRefundNo(), response);
    }

    @Override
    protected PayRefundVo doParseRefundNotify(Map<String, String> params, String body) throws Throwable {
        return switch (channel.getApiVersion()) {
            case WeChatPayClientConfig.API_VERSION_V2 -> doParseRefundNotifyV2(body);
            case WeChatPayClientConfig.API_VERSION_V3 -> doParseRefundNotifyV3(body);
            default -> throw new ServiceException(StrUtil.format("未知的 API 版本({})", channel.getApiVersion()));
        };
    }

    private PayRefundVo doParseRefundNotifyV2(String body) throws WxPayException {
        //1 解析回调
        WxPayRefundNotifyResult response = wxPayService.parseRefundNotifyResult(body);
        WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo();
        //2 构建结果
        PayRefundVo vo = new PayRefundVo();
        if (Objects.equals("SUCCESS", result.getRefundStatus())) {
            return PayRefundVo.successOf(result.getRefundId(), result.getOutRefundNo(), parseDateV2B(result.getSuccessTime()), response);
        }
        return PayRefundVo.failureOf(result.getOutRefundNo(), response);
    }

    private PayRefundVo doParseRefundNotifyV3(String body) throws WxPayException {
        // 1. 解析回调
        WxPayRefundNotifyV3Result response = wxPayService.parseRefundNotifyV3Result(body, null);
        WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult();
        //2 构建结果
        PayRefundVo vo = new PayRefundVo();
        if (Objects.equals("SUCCESS", result.getRefundStatus())) {
            return PayRefundVo.successOf(result.getRefundId(), result.getOutRefundNo(), parseDateV3(result.getSuccessTime()), response);
        }
        return PayRefundVo.failureOf(result.getOutRefundNo(), response);
    }

    @Override
    protected PayRefundVo doGetPayRefund(String refundNo, String payNo) throws WxPayException {
        try {
            return switch (channel.getApiVersion()) {
                case WeChatPayClientConfig.API_VERSION_V2 -> doGetPayRefundV2(refundNo, payNo);
                case WeChatPayClientConfig.API_VERSION_V3 -> doGetPayRefundV3(refundNo, payNo);
                default -> throw new ServiceException(StrUtil.format(" 未知的 API 版本({})", channel.getApiVersion()));
            };
        } catch (WxPayException ex) {
            if (equalsAny(ex.getErrCode(), "REFUNDNOTEXIST", "RESOURCE_NOT_EXISTS")) {
                String errorCode = getErrorCode(ex);
                String errorMessage = getErrorMessage(ex);
                PayRefundVo vo = new PayRefundVo();
                vo.setRefundStatus(PayRefundStatus.FAILURE.getCode());
                vo.setResultCode(errorCode);
                vo.setResultMsg(errorMessage);
                vo.setRefundNo(refundNo);
                vo.setRawData(ex.getXmlString());
                vo.setReturnJson(ex.getXmlString());
                return vo;
            }
            throw ex;
        }
    }

    private PayRefundVo doGetPayRefundV2(String refundNo, String payNo) throws WxPayException {
        // 1. 构建 WxPayRefundRequest 请求
        WxPayRefundQueryRequest request = WxPayRefundQueryRequest.newBuilder()
                .outTradeNo(payNo)
                .outRefundNo(refundNo)
                .build();
        //2 执行请求
        WxPayRefundQueryResult response = wxPayService.refundQuery(request);
        //3 创建返回结果
        PayRefundVo vo = new PayRefundVo();
        if (!Objects.equals("SUCCESS", response.getResultCode())) {
            vo.setRefundStatus(PayRefundStatus.PENDING.getCode());
            vo.setRefundNo(refundNo);
            vo.setRawData(response);
            vo.setReturnJson(JSONUtil.toJsonStr(response));
            return vo;
        }
        WxPayRefundQueryResult.RefundRecord refund = CollUtil.findOne(response.getRefundRecords(), item -> item.getOutRefundNo().equals(refundNo));
        if (refund == null) {
            vo.setRefundStatus(PayRefundStatus.FAILURE.getCode());
            vo.setRefundNo(refundNo);
            vo.setRawData(response);
            vo.setReturnJson(JSONUtil.toJsonStr(response));
            return vo;
        }
        return switch (refund.getRefundStatus()) {
            case "SUCCESS" ->
                    PayRefundVo.successOf(refund.getRefundId(), refundNo, parseDateV2B(refund.getRefundSuccessTime()), response);
            case "PROCESSING" ->
                    PayRefundVo.pendingOf(refund.getRefundId(), refundNo, response); // 退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，资金回流到商户的现金帐号，需要商户人工干预，通过线下或者财付通转账的方式进行退款
            case "CHANGE", "FAIL" -> PayRefundVo.failureOf(refundNo, response);
            default -> throw new ServiceException(StrUtil.format("未知的退款状态({})", refund.getRefundStatus()));
        };
    }

    private PayRefundVo doGetPayRefundV3(String refundNo, String payNo) throws WxPayException {
        // 1. 构建 WxPayRefundRequest 请求
        WxPayRefundQueryV3Request request = new WxPayRefundQueryV3Request();
        request.setOutRefundNo(refundNo);
        //2 执行请求
        WxPayRefundQueryV3Result response = wxPayService.refundQueryV3(request);
        //3 创建返回结果
        return switch (response.getStatus()) {
            case "SUCCESS" ->
                    PayRefundVo.successOf(response.getRefundId(), refundNo, parseDateV3(response.getSuccessTime()), response);
            case "PROCESSING" -> PayRefundVo.pendingOf(response.getRefundId(), refundNo, response); //退款异常
            case "ABNORMAL", "CLOSED" -> PayRefundVo.failureOf(refundNo, response);
            default -> throw new ServiceException(StrUtil.format("未知的退款状态({})", response.getStatus()));
        };

    }

    @Override
    protected PayTransferVo doUnifiedTransfer(PayTransferBo bo) throws Throwable {
        List<TransferBatchesRequest.TransferDetail> transferDetailList = CollUtil.newArrayList();
        TransferBatchesRequest.TransferDetail transferDetail = new TransferBatchesRequest.TransferDetail();
        transferDetail.setOpenid(bo.getOpenId());
        transferDetail.setOutDetailNo(bo.getTransferNo());
        transferDetail.setTransferAmount(bo.getAmount().intValue());
        transferDetail.setTransferRemark(bo.getTransferRemark());
        if(bo.getAmount() > 3L) {
            transferDetail.setUserName(bo.getUserName());
        }
        transferDetailList.add(transferDetail);
        TransferBatchesRequest batchesRequest = new TransferBatchesRequest();
        batchesRequest.setAppid(bo.getWxAppId());
        batchesRequest.setOutBatchNo(bo.getTransferBatchNo());
        batchesRequest.setBatchName(StrUtil.format("用户({})提现", bo.getUserName()));
        batchesRequest.setBatchRemark(StrUtil.format("提现单号：{}", bo.getWithdrawNumber()));
        batchesRequest.setTotalAmount(bo.getAmount().intValue());
        batchesRequest.setTotalNum(1);
        batchesRequest.setTransferDetailList(transferDetailList);
        //执行请求
        TransferBatchesResult response = wxPayService.getTransferService().transferBatches(batchesRequest);
        return switch (response.getBatchStatus()) {
            case "FINISHED" ->
                    PayTransferVo.successOf(bo.getTransferNo(), response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getCreateTime()), response);
            case "ACCEPTED" ->
                    PayTransferVo.acceptedOf(bo.getTransferNo(), response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getCreateTime()), response);
            case "PROCESSING" ->
                    PayTransferVo.processingOf(bo.getTransferNo(), response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getCreateTime()), response);
            case "CLOSED" ->
                    PayTransferVo.failureOf(bo.getTransferNo(), response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getCreateTime()), response);
            default -> throw new ServiceException(StrUtil.format("未知的转账状态({})", response.getBatchStatus()));
        };
    }

    @Override
    protected PayTransferVo doGetPayTransfer(String transferBatchNo, String transferNo) throws Throwable {
        // 1. 构建 QueryTransferBatchesRequest 请求
        QueryTransferBatchesRequest request = new QueryTransferBatchesRequest();
        TransferBatchDetailResult response = wxPayService.getTransferService().transferBatchesOutBatchNoDetail(transferBatchNo, transferNo);
        return switch (response.getDetailStatus()) {
            case "SUCCESS" ->
                    PayTransferVo.successOf(transferNo, response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getInitiateTime()), response);
            case "INIT" ->
                    PayTransferVo.of(PayTransferStatus.INIT.getCode(), transferNo, response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getInitiateTime()), response);
            case "WAIT_PAY" ->
                    PayTransferVo.of(PayTransferStatus.WAIT_PAY.getCode(), transferNo, response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getInitiateTime()), response);
            case "PROCESSING" ->
                    PayTransferVo.processingOf(transferNo, response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getInitiateTime()), response);
            case "FAIL" ->
                    PayTransferVo.failureOf(transferNo, response.getOutBatchNo(), response.getBatchId(), parseDateV3(response.getInitiateTime()), response);
            default -> throw new ServiceException(StrUtil.format("未知的转账状态({})", response.getDetailStatus()));
        };
    }

    @Override
    protected PayTransferVo doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
        WxPayTransferBatchesNotifyV3Result response = wxPayService.parseTransferBatchesNotifyV3Result(body, null);
        WxPayTransferBatchesNotifyV3Result.DecryptNotifyResult result = response.getResult();
        //构建结果
        PayTransferVo vo = new PayTransferVo();
        if(Objects.equals("FINISHED", result.getBatchStatus())){
            return PayTransferVo.successOf("", result.getOutBatchNo(),result.getBatchId(),parseDateV3(result.getUpdateTime()),result);
        }
        return PayTransferVo.failureOf(result.getOutBatchNo(), result.getBatchId(), result);
    }

    private File createTempFile(byte[] content) {
        File file = this.createTempFile();
        FileUtil.writeBytes(content, file);
        return file;
    }

    /**
     * 创建临时文件
     */
    private File createTempFile(String content) {
        File file = this.createTempFile();
        FileUtil.writeUtf8String(content, file);
        return file;
    }

    //创建临时文件
    //jvm退出时，自动删除
    @SneakyThrows
    private File createTempFile() {
        File file = File.createTempFile(IdUtil.simpleUUID(), null);
        file.deleteOnExit();
        return file;
    }

    static Integer parseStatus(String tradeState) {
        return switch (tradeState) {
            case "NOTPAY", "USERPAYING" -> // 支付中，等待用户输入密码（条码支付独有）
                    PayOrderStatus.PENDING.getCode();
            case "SUCCESS" -> PayOrderStatus.SUCCESS.getCode();
            case "REFUND" -> PayOrderStatus.REFUND.getCode(); // 已撤销（刷卡支付独有）
            case "CLOSED", "REVOKED", "PAYERROR" -> //支付失败（其它原因，如银行返回失败）
                    PayOrderStatus.CLOSED.getCode();
            default -> throw new ServiceException(StrUtil.format("未知的支付状态({})", tradeState));
        };
    }

    static String getErrorCode(WxPayException e) {
        if (StrUtil.isNotEmpty(e.getErrCode())) {
            return e.getErrCode();
        }
        if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) {
            return "CUSTOM_ERROR";
        }
        return e.getReturnCode();
    }

    static String getErrorMessage(WxPayException e) {
        if (StrUtil.isNotEmpty(e.getErrCode())) {
            return e.getErrCodeDes();
        }
        if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) {
            return e.getCustomErrorMsg();
        }
        return e.getReturnMsg();
    }

    static String formatDateV2(LocalDateTime time) {
        return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
    }

    static LocalDateTime parseDateV2(String time) {
        return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN);
    }

    static LocalDateTime parseDateV2B(String time) {
        return LocalDateTimeUtil.parse(time, NORM_DATETIME_PATTERN);
    }

    static String formatDateV3(LocalDateTime time) {
        return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN);
    }

    static LocalDateTime parseDateV3(String time) {
        return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN);
    }

    @SafeVarargs
    static <T> boolean equalsAny(T obj, T... array) {
        return Arrays.asList(array).contains(obj);
    }
}
